package com.personal.dataanalyse.enums;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.personal.core.data.DataColumn;
import com.personal.core.data.DataColumns;
import com.personal.core.data.DataRow;
import com.personal.core.utils.CoreUtil;
import com.personal.core.utils.ReGularUtil;
import com.personal.dataanalyse.consts.FieldConsts;
import com.personal.dataanalyse.reportmanage.entity.DataColumnReportEx;
import com.personal.dataanalyse.reportmanage.entity.DataRowReportEx;
import com.personal.dataanalyse.reportmanage.util.ModelUtil;

/**
 * 合计类型
 * @author cuibo
 *
 */
public enum TotalTypeEnum
{
    原值, 求和, 求平均, 求最大值, 求最小值, 求占比;

    /**
     * 处理合计方式
     * @param reportRow   报表行
     * @param reportColumn  单个报表列信息
     * @param cacheMap  缓存数据的Map（在后面求平均，等信息时需要用到）
     * @param dataRow 数据行
     */
    public static void handleTotalType(DataRowReportEx reportRow, DataColumnReportEx reportColumn,
            Map<String, Object> cacheMap, DataRow dataRow)
    {
        Map<String, Object> data = dataRow.getItemMap();
        if (data == null || data.isEmpty())
        {
            return;
        }
        if (CoreUtil.isEmpty(reportColumn.getFieldDataSql()))
        {
            return;
        }
        String totalTypeStr = reportColumn.getTotalType();
        if (CoreUtil.isEmpty(totalTypeStr))
        {
            // 默认为求和
            totalTypeStr = 求和.toString();
            reportColumn.setTotalType(totalTypeStr);
        }
        TotalTypeEnum totalType = TotalTypeEnum.valueOf(totalTypeStr);

        String calType = reportColumn.getCalculateType();
        if (CoreUtil.isEmpty(calType))
        {
            calType = CalculateTypeEnum.先计算后汇总.toString();
            reportColumn.setCalculateType(calType);
        }
        // 对于表达式，计算每个细项的求和值,  不能重复求和
        if (reportColumn.isExpType())
        {
            // 先汇总后计算 需要计算每个的合计
            String[] arr = ReGularUtil.EXPANDKHPATTERNANDABS.split(reportColumn.getFieldDataSql());
            if (arr == null || arr.length == 0)
            {
                return;
            }
            // 计算每个细项的值,存入缓存,arr需要去重
            Set<String> set = new HashSet<String>(Arrays.asList(arr));
            // 去除空格
            for (String string : arr)
            {
                // 是数字常量不允许求和
                if (!ModelUtil.checkLegalFieldDataSql(string))
                {
                    continue;
                }
                set.add(string.trim());
            }
            for (String single : set)
            {
                String key = reportColumn.getColumnName() + single + 求和.toString();
                cacheMap.put(key, CoreUtil.addWithNull(cacheMap.get(key), data.get(single)));
            }
        }
        Object oldValue = null;
        Object newValue = null;
        switch (totalType)
        {
        case 原值:
            if (reportColumn.isExpType())
            {
                reportRow.setValue(reportColumn, CoreUtil.calculateExByAviWithAbs(reportColumn.getFieldDataSql(), data));
            } else
            {
                // 缓存求和值
                String key = reportColumn.getColumnName() + reportColumn.getFieldDataSql() + 求和.toString();
                cacheMap.put(key, CoreUtil.addWithNull(cacheMap.get(key), data.get(reportColumn.getFieldDataSql())));
                reportRow.setValue(reportColumn, data.get(reportColumn.getFieldDataSql()));
            }
            break;
        case 求和:
        case 求占比:
        case 求平均:
            // 求和，求占比，求平均的处理方式 都和求和的处理方式一致。
            if (reportColumn.isExpType())
            {
                // 要区分是：先计算后汇总  还是 :先汇总后计算
                if (CalculateTypeEnum.先计算后汇总.toString().equals(calType))
                {
                    // 先计算后汇总
                    reportRow.setValue(
                            reportColumn,
                            CoreUtil.addWithNull(reportRow.getItemMap().get(reportColumn.getColumnName()),
                                    CoreUtil.calculateExByAviWithAbs(reportColumn.getFieldDataSql(), data)));
                }
            } else
            {
                // 缓存求和值, 不能重复累加
                String key = reportColumn.getColumnName() + reportColumn.getFieldDataSql() + 求和.toString();
                cacheMap.put(key, CoreUtil.addWithNull(cacheMap.get(key), data.get(reportColumn.getFieldDataSql())));
                reportRow.setValue(reportColumn,
                        CoreUtil.addWithNull(reportRow.getItemMap().get(reportColumn.getColumnName()), data.get(reportColumn.getFieldDataSql())));
            }
            break;
        case 求最大值:
            if (FieldDataTypeEnum.日期.toString().equals(reportColumn.getDataType()))
            {
                if (reportRow.getItemMap().get(reportColumn.getColumnName()) == null)
                {
                    oldValue = CoreUtil.DATETIME_QUERY_MIN;
                } else
                {
                    oldValue = CoreUtil.parseDate(reportRow.getItemMap().get(reportColumn.getColumnName()));
                }
                newValue = CoreUtil.parseDate(data.get(reportColumn.getFieldDataSql()));
                if (CoreUtil.compareDate((Date) newValue, (Date) oldValue) > 0)
                {
                    reportRow.setValue(reportColumn, newValue);
                }
            } else if (FieldDataTypeEnum.数值.toString().equals(reportColumn.getDataType()))
            {
                // 先不处理先汇总后计算的问题
                if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
                {
                    return;
                }
                if (reportRow.getItemMap().get(reportColumn.getColumnName()) == null)
                {
                    oldValue = Double.MIN_VALUE;
                } else
                {
                    oldValue = CoreUtil.parseDbl(reportRow.getItemMap().get(reportColumn.getColumnName()));
                }
                if (reportColumn.isExpType())
                {
                    newValue = CoreUtil.parseDbl(CoreUtil.calculateExByAviWithAbs(reportColumn.getFieldDataSql(), data));
                } else
                {
                    newValue = CoreUtil.parseDbl(data.get(reportColumn.getFieldDataSql()));
                }
                if (CoreUtil.compareNumberNoPrecision(newValue, oldValue) > 0)
                {
                    reportRow.setValue(reportColumn, newValue);
                }
            }
            break;
        case 求最小值:
            if (FieldDataTypeEnum.日期.toString().equals(reportColumn.getDataType()))
            {
                if (reportRow.getItemMap().get(reportColumn.getColumnName()) == null)
                {
                    oldValue = CoreUtil.DATETIME_QUERY_MAX;
                } else
                {
                    oldValue = CoreUtil.parseDate(reportRow.getItemMap().get(reportColumn.getColumnName()));
                }
                newValue = CoreUtil.parseDate(data.get(reportColumn.getFieldDataSql()));
                if (CoreUtil.compareDate((Date) newValue, (Date) oldValue) < 0)
                {
                    reportRow.setValue(reportColumn, newValue);
                }
            } else if (FieldDataTypeEnum.数值.toString().equals(reportColumn.getDataType()))
            {
                // 先不处理先汇总后计算的问题
                if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
                {
                    return;
                }
                if (reportRow.getItemMap().get(reportColumn.getColumnName()) == null)
                {
                    oldValue = Double.MAX_VALUE;
                } else
                {
                    oldValue = CoreUtil.parseDbl(reportRow.getItemMap().get(reportColumn.getColumnName()));
                }
                if (reportColumn.isExpType())
                {
                    newValue = CoreUtil.parseDbl(CoreUtil.calculateExByAviWithAbs(reportColumn.getFieldDataSql(), data));
                } else
                {
                    newValue = CoreUtil.parseDbl(data.get(reportColumn.getFieldDataSql()));
                }
                if (CoreUtil.compareNumberNoPrecision(newValue, oldValue) < 0)
                {
                    reportRow.setValue(reportColumn, newValue);
                }
            }
            break;
        default:
            break;
        }

    }

    /**
     * 对于先汇总后计算的数据和求占比的数据和求平均值的数据需要再次处理
     * @param reportRow   报表行
     * @param cacheMap   缓存的数据
     * @param columns   所有列信息
     */
    public static void reHandleTotalType(DataRow reportRow, Map<String, Object> cacheMap, DataColumns columns)
    {
        if (reportRow == null || columns == null || columns.isEmpty())
        {
            return;
        }
        DataColumnReportEx reportColumn = null;

        // 原值
        Object oldValue = null;
        Object newValue = null;
        for (DataColumn dataColumn : columns)
        {
            if (!(dataColumn instanceof DataColumnReportEx))
            {
                continue;
            }
            reportColumn = (DataColumnReportEx) dataColumn;
            String fieldDataSql = reportColumn.getFieldDataSql();
            if (CoreUtil.isEmpty(fieldDataSql))
            {
                continue;
            }
            // 计算列过滤
            if (!ModelFieldTypeEnum.isCommonOrGroupField(reportColumn.getFieldType()))
            {
                continue;
            }
            TotalTypeEnum totalType = valueOf(reportColumn.getTotalType());
            String calType = reportColumn.getCalculateType();

            switch (totalType)
            {
            case 求和:
                // 非表达式的不需要考虑
                if (!reportColumn.isExpType())
                {
                    continue;
                }
                // 要区分是：先计算后汇总  还是 :先汇总后计算
                if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
                {
                    reportRow.setValue(reportColumn, calXhzhjs(fieldDataSql, reportColumn, cacheMap));
                }
                break;
            case 求最大值:
                // 2017 07 11 新增求最值也要区分是先计算后汇总，还是先汇总后计算
                if (reportColumn.isExpType())
                {
                    continue;
                }
                // 要区分是：先计算后汇总  还是 :先汇总后计算
                if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
                {
                    if (reportRow.getItemMap().get(reportColumn.getColumnName()) == null)
                    {
                        oldValue = Double.MIN_VALUE;
                    } else
                    {
                        oldValue = CoreUtil.parseDbl(reportRow.getItemMap().get(reportColumn.getColumnName()));
                    }
                    newValue = calXhzhjs(fieldDataSql, reportColumn, cacheMap);
                    if (CoreUtil.compareNumberNoPrecision(newValue, oldValue) > 0)
                    {
                        reportRow.setValue(reportColumn, newValue);
                    }
                }
                break;
            case 求最小值:
                // 2017 07 11 新增求最值也要区分是先计算后汇总，还是先汇总后计算
                if (reportColumn.isExpType())
                {
                    continue;
                }
                // 要区分是：先计算后汇总  还是 :先汇总后计算
                if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
                {
                    if (reportRow.getItemMap().get(reportColumn.getColumnName()) == null)
                    {
                        oldValue = Double.MAX_VALUE;
                    } else
                    {
                        oldValue = CoreUtil.parseDbl(reportRow.getItemMap().get(reportColumn.getColumnName()));
                    }
                    newValue = calXhzhjs(fieldDataSql, reportColumn, cacheMap);
                    if (CoreUtil.compareNumberNoPrecision(newValue, oldValue) < 0)
                    {
                        reportRow.setValue(reportColumn, newValue);
                    }
                }
                break;
            case 求占比:
                // 非表达式的不需要考虑
                if (!reportColumn.isExpType())
                {
                    continue;
                }
                // 要区分是：先计算后汇总  还是 :先汇总后计算
                if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
                {
                    reportRow.setValue(reportColumn, calXhzhjs(fieldDataSql, reportColumn, cacheMap));
                }
                break;
            case 求平均:
                // 每列的匹配个数均不一样
                String countKey = reportColumn.getColumnName() + FieldConsts.STR_COUNT;
                if (!cacheMap.containsKey(countKey))
                {
                    // 匹配个数为空
                    reportRow.setValue(reportColumn, null);
                    continue;
                }
                int matchCount = CoreUtil.parseInt(cacheMap.get(countKey));
                if (matchCount > 0)
                {
                    reportRow.setValue(reportColumn, CoreUtil.divideWithNull(reportRow.getItemMap().get(reportColumn.getColumnName()), matchCount));
                } else
                {
                    reportRow.setValue(reportColumn, null);
                }
                break;
            default:
                break;
            }
        }
    }

    /**
     * 计算占比合计
     * @param columns
     * @param zbCacheMap
     * @param zbHjMap
     */
    public static void calZbHjMap(DataColumns columns, Map<DataColumn, Set<DataRow>> zbCacheMap,
                                  Map<String, Object> zbHjMap)
    {
        DataColumnReportEx reportColumn = null;
        for (DataColumn dataColumn : columns)
        {
            if (!(dataColumn instanceof DataColumnReportEx))
            {
                continue;
            }
            reportColumn = (DataColumnReportEx) dataColumn;
            String fieldDataSql = reportColumn.getFieldDataSql();
            if (CoreUtil.isEmpty(fieldDataSql))
            {
                continue;
            }
            // 只需要处理是普通列获取列维度指标
            if (!ModelFieldTypeEnum.isCommonOrGroupField(reportColumn.getFieldType()))
            {
                continue;
            }
            String totalType = reportColumn.getTotalType();
            String calType = reportColumn.getCalculateType();
            if (求占比.toString().equals(totalType))
            {
                calZbHjMap(reportColumn, zbCacheMap, calType, fieldDataSql, zbHjMap);
            }
        }
    }

    private static void calZbHjMap(DataColumnReportEx reportColumn, Map<DataColumn, Set<DataRow>> zbCacheMap,
            String calType, String fieldDataSql, Map<String, Object> zbHjMap)
    {
        if (reportColumn.isExpType())
        {
            if (CalculateTypeEnum.先汇总后计算.toString().equals(calType))
            {
                String[] arr = ReGularUtil.EXPANDKHPATTERNANDABS.split(reportColumn.getFieldDataSql());
                if (arr == null || arr.length == 0)
                {
                    return;
                }
                Map<String, Object> thisColHj = new HashMap<String, Object>();
                for (DataRow dataRow : zbCacheMap.get(reportColumn))
                {
                    for (String string : arr)
                    {
                        // 是数字常量不允许求和
                        if (!ModelUtil.checkLegalFieldDataSql(string))
                        {
                            continue;
                        }
                        thisColHj.put(string, CoreUtil.addWithNull(dataRow.getItemMap().get(string), thisColHj.get(string)));
                    }
                }
                zbHjMap.put(reportColumn.getColumnName(), CoreUtil.calculateExByAviWithAbs(fieldDataSql, thisColHj));
            } else
            {
                for (DataRow dataRow : zbCacheMap.get(reportColumn))
                {
                    zbHjMap.put(
                            reportColumn.getColumnName(),
                            CoreUtil.addWithNull(CoreUtil.calculateExByAviWithAbs(fieldDataSql, dataRow.getItemMap()),
                                    zbHjMap.get(reportColumn.getColumnName())));
                }
            }
        } else
        {
            for (DataRow dataRow : zbCacheMap.get(reportColumn))
            {
                zbHjMap.put(
                        reportColumn.getColumnName(),
                        CoreUtil.addWithNull(dataRow.getItemMap().get(fieldDataSql),
                                zbHjMap.get(reportColumn.getColumnName())));
            }
        }
    }

    /**
     * 计算先汇总后计算的值
     * @param fieldDataSql
     * @param reportColumn
     * @param cacheMap
     */
    private static Object calXhzhjs(String fieldDataSql, DataColumnReportEx reportColumn, Map<String, Object> cacheMap)
    {
        String[] arr = ReGularUtil.EXPANDKHPATTERNANDABS.split(reportColumn.getFieldDataSql());
        if (arr == null || arr.length == 0)
        {
            return null;
        }
        // 计算每个细项的值,存入缓存
        Map<String, Object> thisMap = new HashMap<String, Object>();
        for (String single : arr)
        {
            // 是数字常量直接参与计算
            if (!ModelUtil.checkLegalFieldDataSql(single))
            {
                continue;
            }
            thisMap.put(single, cacheMap.get(reportColumn.getColumnName() + single + 求和.toString()));
        }
        return CoreUtil.calculateExByAviWithAbs(fieldDataSql, thisMap);
    }

    /**
     * 求占比
     * @param srow   报表行
     * @param columns   所有列信息
     * @param zbHjMap   占比合计缓存
     */
    public static void calProportion(DataRow reportRow, DataColumns columns, Map<String, Object> zbHjMap)
    {
        for (DataColumn dataColumn : columns)
        {
            if (zbHjMap.containsKey(dataColumn.getColumnName()))
            {
                reportRow.setValue(
                        dataColumn,
                        CoreUtil.multiplyWithNull(
                                CoreUtil.divideWithNull(reportRow.getItemMap().get(dataColumn.getColumnName()),
                                        zbHjMap.get(dataColumn.getColumnName())), 100));
            }
        }
    }
}
